package com.hzw.saas.service.hpc.util;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.Method;
import com.hzw.saas.common.util.PathUtils;
import com.hzw.saas.common.util.SignatureUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpException;
import org.springframework.http.HttpMethod;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 青云HPC HTTP请求客户端
 *
 * @author zzl
 * @since 08/18/2021
 */
@Slf4j
public class QingCloudClient {

    private final String gateway;
    private final String accessKeyId;
    private final String secretAccessKey;
    private final String version;
    private final String signatureMethod;
    private final String signatureVersion;

    public QingCloudClient(String gateway, String accessKeyId, String secretAccessKey, String version, String signatureMethod, String signatureVersion) {
        this.gateway = gateway;
        this.accessKeyId = accessKeyId;
        this.secretAccessKey = secretAccessKey;
        this.version = version;
        this.signatureMethod = signatureMethod;
        this.signatureVersion = signatureVersion;
    }

    /**
     * 发送请求
     *
     * @param httpMethod 请求方式
     * @param uri        请求uri
     * @param urlParams  路径参数
     * @return 请求结果
     * @throws HttpException 请求结果非2XX
     */
    public String request(HttpMethod httpMethod, String uri, Map<String, String> urlParams) throws HttpException {
        return this.request(httpMethod, uri, urlParams, "");
    }

    /**
     * 发送请求
     *
     * @param httpMethod  请求方式
     * @param uri         请求uri
     * @param urlParams   路径参数
     * @param requestBody 请求体（Json字符串）
     * @return 请求结果
     * @throws HttpException 请求结果非2XX
     */
    public String request(HttpMethod httpMethod, String uri, Map<String, String> urlParams, String requestBody) throws HttpException {
        // init params
        if (Objects.isNull(urlParams)) urlParams = new HashMap<>();
        this.assemblePublicParams(urlParams);
        StringBuilder urlParamsBuilder = SignatureUtil.generateUrlParamsStr(urlParams);

        // generate signature
        String string2Signature = SignatureUtil.generateString2Signature(httpMethod, uri, urlParamsBuilder.toString(), requestBody);
        String signature = SignatureUtil.generateSignature(this.signatureMethod, this.secretAccessKey, string2Signature);
        this.appendSignature(urlParamsBuilder, signature);

        // request
        String url = this.generateUrl(uri, urlParamsBuilder.toString());
        log.debug("request url: {}", url);
        HttpRequest httpRequest = new HttpRequest(url);
        httpRequest.setMethod(this.getMethod(httpMethod));
        if (!Objects.equals(httpMethod, HttpMethod.GET)) {
            httpRequest.contentType("application/json");
            if (StrUtil.isNotBlank(requestBody)) {
                httpRequest.body(requestBody);
            }
        }
        HttpResponse response = httpRequest.execute();
        String body = response.body();
//        log.debug("qc response body: \n{}", body);
        if (!response.isOk()) {
            throw new HttpException(body);
        }
        return body;
    }

    /**
     * 生成请求URL
     *
     * @param uri
     * @param urlParamsStr
     * @return
     */
    private String generateUrl(String uri, String urlParamsStr) {
        String url = PathUtils.connectUri(this.gateway, uri);
        return url.concat("?").concat(urlParamsStr);
    }

    /**
     * 组装公共参数
     *
     * @param params
     */
    private void assemblePublicParams(Map<String, String> params) {
        if (!params.containsKey("timestamp")) {
            params.put("timestamp", DateUtil.format(new Date(), SignatureUtil.TIME_PATTERN));
        }
        params.put("access_key_id", this.accessKeyId);
        params.put("version", this.version); // 1
        params.put("signature_method", this.signatureMethod); //HmacSHA256 或 HmacSHA1
        params.put("signature_version", this.signatureVersion); // 1
    }

    /**
     * 路径参数增加签名
     *
     * @param urlParamsBuilder 路径参数字符串
     * @param signature        签名
     */
    private void appendSignature(StringBuilder urlParamsBuilder, String signature) {
        if (StrUtil.isNotBlank(urlParamsBuilder))
            urlParamsBuilder.append("&");
        urlParamsBuilder.append("signature").append("=").append(signature);
    }

    private Method getMethod(HttpMethod httpMethod) {
        switch (httpMethod) {
            case GET:
                return Method.GET;
            case HEAD:
                return Method.HEAD;
            case POST:
                return Method.POST;
            case PUT:
                return Method.PUT;
            case PATCH:
                return Method.PATCH;
            case DELETE:
                return Method.DELETE;
            case OPTIONS:
                return Method.OPTIONS;
            case TRACE:
                return Method.TRACE;
        }
        throw new IllegalArgumentException("请求方式异常");
    }

}
